#include "serialgchannel.h"

#include <set>
#include <time.h> 
#ifdef WIN32
#define usleep(x) Sleep(x)
#endif

#include "business_def.h"
#include "Log.h"
#include "pfunc.h"

SerialGChannel::SerialGChannel(int gid_)
	: GatherChannel(gid_)
	, running(true)
	, serial_open_flag(false)
	, serialPortStateTime(static_cast<unsigned int>(time(NULL)))
	, allCmdFlag(1)
	, error_ret_count(0)
{
	init(gid_);
};

SerialGChannel::~SerialGChannel()
{
	running = false;
	stopSms();
};

void SerialGChannel::init(int gid_)
{
	BusinessDef *ptrBDef = BusinessDef::getInstance();
    if(!ptrBDef->getSerialInfoByGID(gid_,serialarg))
    {
        Print_WARN("getSerialInfoByGID error!\n");
    }
	//单次m_ssg读取时间=readCount*readSleep
	m_ssg.setReadCount(serialarg.readCount);//数据读取次数
	m_ssg.setReadSleep(serialarg.readSleep);//数据读取等待
	//
	allCmdFlag = cmdlist.cmd_totalcall.empty()?allCmdFlag:2;
}

void SerialGChannel::serial_call()
{
	//从缓存读取总召命令下发,并读取返回命令作解析处理
	if(serial_open_flag)
	{
		try {
			ChannelCmd w_item;
			if(WriteDatas->pop(w_item))
			{
				char atres[256] = { 0 };
				char _exception[256] = { 0 };
				bool wf = false;//数据下行标识
				bool ret = this->m_ssg.sendmsg((const char*)w_item.Buf, atres, _exception, wf,w_item.acsiif);
				
				if (!ret) 
				{
					if (1 == protodefs.retValNull && 0 == strcmp("command-out-time", _exception))
					{//指定无返回
						ret = true;
					}
					else {//again
						ret = this->m_ssg.sendmsg((const char*)w_item.Buf, atres, _exception, wf,w_item.acsiif);
					}
				}
				unsigned long taskID = w_item.taskID;
				if (w_item.controlF)//control cmd make log
				{
					CLogger::createInstance()->Log(MsgInfo,
						"TaskID[%lu] and down_node[6] SerialPort downControl, time(%s)"
						", SerialGather(%d,%s), msg(%s),atres(%s),exception(%s)"
						, taskID, pyfree::getCurrentTime().c_str()
						, gatheratts.id, gatheratts.name.c_str()
						, w_item.Buf, atres, _exception);
				}
				else {
					if (taskID <= 0)
					{
						taskID = pyfree::getTaskIDFromDateTime();//任务编号创建,一般为总召指令
					}
				}
				//返回指令处理
				msgResponse(ret, (const char*)w_item.Buf, atres, _exception, wf, w_item.controlF, taskID);
				if (w_item.wait > 0)
				{
					usleep(w_item.wait*1000);
				}
			}
		}
		catch (...) {
			CLogger::createInstance()->Log(MsgInfo
				, "get cmd cache is error, cann't down control these cmd to SerialGather(%d,%s)!"
			, gatheratts.id, gatheratts.name.c_str());
		}
	}else{
		if (!open())
		{
			sleep(5);
		}
	}
}

void SerialGChannel::push_total_call()
{
	//将总召命令写入缓存
	if (serial_open_flag&&!cmdlist.cmd_totalcall.empty()) 
	{
		unsigned long curmsec = static_cast<unsigned long>(clock());
	#ifdef __linux__
		curmsec = static_cast<unsigned long>(curmsec/1000);
	#endif
		if (cmdlist.time_totalcall < curmsec)
		{
			cmdlist.time_totalcall = curmsec + protodefs.totalcallsleep;
			if (WriteDatas->size() < 2 * static_cast<int>(cmdlist.cmd_totalcall.size()))
			{
				for (std::list<std::string>::iterator it = cmdlist.cmd_totalcall.begin();
					it != cmdlist.cmd_totalcall.end(); ++it)
				{
					sendmsg((*it).c_str());
				}
			}
		}
	}
}

void SerialGChannel::data_time_up()
{
	//间隔发送串口打开状态,下行通讯状态,上行通讯状态及采集点状态
	unsigned int cursec = static_cast<unsigned int>(time(NULL));
	if (serialPortStateTime < cursec)
	{
		serialPortStateTime = cursec + gatheratts.timePush;
		TimeUpState();
	}
}

//开启任务
bool SerialGChannel::startSms()
{
	char arg_[64]={0};
	sprintf(arg_, "%d%s%d", serialarg.DataBit,serialarg.Parity.c_str(),serialarg.StopBit);
	int ret = m_ssg.Open(gatheratts.name.c_str(), serialarg.BaudRate, arg_,ctb::SerialPort::NoFlowControl);
	if( -1 ==  ret)
	{
		cstate.m_open_success_log = false;
		if (!cstate.m_open_fail_log)
		{
			cstate.m_open_fail_log = true;
			CLogger::createInstance()->Log(MsgError,
				"SerialGatherID(%d) open serical(%s %d,%s) fail! [%s %s %d]"
				, gatheratts.id, gatheratts.name.c_str(), serialarg.BaudRate, arg_
				, __FILE__, __FUNCTION__, __LINE__);
		}
		return false;
	}
	serial_open_flag = true;
	cstate.m_open_fail_log = false;
	if (!cstate.m_open_success_log) 
	{
		cstate.m_open_success_log = true;
		//qDebug()<<QString("%1  be open successful!").arg(port);
		CLogger::createInstance()->Log(MsgInfo,
			"SerialGather(%d,%s)  be open successful![%s %s %d]"
			, gatheratts.id, gatheratts.name.c_str()
			, __FILE__, __FUNCTION__, __LINE__);
	}
	return true;
}

//关闭
void SerialGChannel::stopSms()
{
	try{
		if (!serial_open_flag)
		{
			return;
		}
		serial_open_flag = false;
		m_ssg.Close();
#ifdef DEBUG
		Print_NOTICE("m_ssg.Close()\n");
#endif
		//when the port close, then will init point value again.
		if (gatheratts.linkInitKey) { //将重新打开串口后,具有总召查询指令支持的设备可初始化点值
			pointInitReset();
		}
	}catch(...){
        //Print_NOTICE("SerialGChannel::destroy fail\n");
		CLogger::createInstance()->Log(MsgError,
			"SerialGChannel::destroy SerialGather(%d,%s) fail![%s %s %d]"
			, gatheratts.id, gatheratts.name.c_str()
			, __FILE__, __FUNCTION__, __LINE__);
    }
}

void* SerialGChannel::run()
{
	CLogger::createInstance()->Log(MsgInfo
		, "run serial port SerialGather(%d,%s) thread now!"
		, gatheratts.id, gatheratts.name.c_str());
	while(running)
	{
		serial_call();
		push_total_call();
		data_time_up();
		usleep(1);
	}
	return 0;
};

bool SerialGChannel::open()
{
	bool ret = startSms();
	this->setValue(-1,ret ? float(1.0) : float(0.0),100088);//更新串口打开状态
	return ret;
}
//信息发送到队列
void SerialGChannel::sendmsg( const char* text,int _wait, bool appendf,bool acsiif, unsigned long _taskID)
{
	if (!serial_open_flag)
	{
		if (!open())
		{
			return;
		}
	}
	if(appendf&&WriteDatas->size()>static_cast<int>(msg_Max_count))
	{
		CLogger::createInstance()->Log(MsgInfo
			, "SerialGather(%d,%s) msg cache is full, cann't add the new msg(%s) to it!"
			, gatheratts.id, gatheratts.name.c_str(), text);
		return;
	}
	// else{
	// 	Print_NOTICE("add msg to cache:%s\n",text);
	// }

	ChannelCmd cmdinfo((unsigned char*)text,static_cast<int>(strlen(text)),!appendf,_taskID,_wait,acsiif);
	if(appendf){
		WriteDatas->add(cmdinfo);
	}else
	{
		WriteDatas->add_front(cmdinfo);
	}
};

void SerialGChannel::msgResponse(bool ret, const char *text,char *atres,char* exception,bool wf
	, bool controlf, unsigned long _taskID)
{
	// cstate.m_wf = wf;//下行(下控)状态
	// cstate.m_rf = ret;//上行(返回)状态
	if (ret)
	{
		cstate.m_error_ret_max_log = false;
		if (1 == protodefs.retValNull)
		{
			return;
		}
		std::string _otherDesc = "";
		if(protodefs.oldState>0)
		{
			_otherDesc = std::string((char*)text);
		}
		std::string atres_ = std::string(atres);
		msgAnalysis(atres,_otherDesc,_taskID,controlf);
	}
	else {
		if (0 != allCmdFlag) 
		{
			error_ret_count++;
			if ((1 == allCmdFlag&&error_ret_count > error_ret_max)
				|| (2 == allCmdFlag&&error_ret_count > error_ret_max_AllCmd))
			{
				if (!cstate.m_error_ret_max_log) 
				{
					cstate.m_error_ret_max_log = true;
					CLogger::createInstance()->Log(MsgInfo
						, "SerialGather(%d,%s) error_ret_count:%d,reset it."
						, gatheratts.id, gatheratts.name.c_str(), error_ret_count);
				}
				stopSms();
				open();
				error_ret_count = 0;
			}
		}
	}
};

void SerialGChannel::downControl(int _exetype, int _type, int _pid, float _val, unsigned long _taskID)
{
	Print_NOTICE("etype(%d),type(%d),pid(%d),val(%.2f)\n", _exetype, _type, _pid, _val);
	std::string _cmd = "";
	int checktype = 0;
	unsigned long dev_addr = 1;
	if (getCmd(_exetype, _type, _pid, _val, _cmd, checktype,dev_addr, _taskID))
	{
		Print_NOTICE("sendmsg(%s)\n",_cmd.c_str());
		sendmsg(_cmd.c_str(), -1, false, 9 == checktype ? true : false,_taskID);
	}
	else {
		CLogger::createInstance()->Log(MsgWarn,
			"TaskID[%lu] and down_node[5-2] GatherChannel(%d,%s) downControl(%d,%d,%d,%.2f) getCmd fail. [%s %s %d]"
			, _taskID, gatheratts.id,gatheratts.name.c_str()
			, _exetype, _type, _pid, _val
			, __FILE__, __FUNCTION__, __LINE__);
	}
};
